﻿using System.Diagnostics;
using System.IO;
using System.Text;
using System.Web.Mvc.Html;
using SlamCms.Common;
using SlamCms.Web.Mvc;
using System.Text.RegularExpressions;

namespace System.Web.Mvc
{
	public static class ControllerExtensions
	{
		[DebuggerStepThrough]
		public static ActionResult NotFound(this Controller controller, string message = null)
		{
			// this is basically to be handled as an exception
			throw new HttpException(404, message ?? "The page you're looking for doesn't exist");
		}

		[DebuggerStepThrough]
		public static ActionResult NotAuthorized(this Controller controller, string message = null)
		{
			// this is basically to be handled as an exception
			throw new HttpException(401, message ?? "You're not authorized to see this page");
		}

		public static JavascriptFunctionResult JavascriptFunction(this Controller controller, string javascriptFunction)
		{
			return new JavascriptFunctionResult(javascriptFunction);
		}

		public static JsonpResult Jsonp(this Controller controller, object data)
		{
			return new JsonpResult(data);
		}

		public static EmbeddedResourceFileResult EmbeddedResource(this Controller controller, string name, string contentType = null)
		{
			return new EmbeddedResourceFileResult(name, contentType);
		}

		public static PartialJavascriptViewResult PartialJavascriptView(this Controller controller)
		{
			return controller.PartialJavascriptView(null, null);
		}

		public static PartialJavascriptViewResult PartialJavascriptView(this Controller controller, string viewName)
		{
			return controller.PartialJavascriptView(viewName, null);
		}

		public static PartialJavascriptViewResult PartialJavascriptView(this Controller controller, object model)
		{
			return controller.PartialJavascriptView(null, model);
		}

		public static PartialJavascriptViewResult PartialJavascriptView(this Controller controller, string viewName, object model)
		{
			if (model != null)
			{
				controller.ViewData.Model = model;
			}
			var result = new PartialJavascriptViewResult();
			result.ViewName = viewName;
			result.ViewData = controller.ViewData;
			result.TempData = controller.TempData;
			return result;
		}

		public static ViewResult MessageView(this Controller controller, string title, string description, Link link = null)
		{
			return controller.MessageView(null, title, description, link);
		}

		public static ViewResult MessageView(this Controller controller, string viewName, string title, string description, Link link = null)
		{
			var model = new MessageViewModel()
			{
				Title = title.ToHtml(),
				Description = description.ToHtml(),
				Link = link
			};

			return controller.MessageView(viewName, model);
		}

		public static ViewResult MessageView(this Controller controller, string viewName, MessageViewModel model)
		{
			var view = new ViewResult();

			view.TempData = controller.TempData;
			view.ViewData = controller.ViewData;
			
			if (model != null)
				view.ViewData.Model = model;

			if (viewName != null)
				view.ViewName = viewName;
			else
				view.ViewName = "Message";

			return view;
		}

		public static JavascriptEmbeddedHtmlViewResult JavascriptEmbeddedHtml(this Controller controller, string viewName, object model = null)
		{
			return new JavascriptEmbeddedHtmlViewResult(viewName, model);
		}

		public static RedirectToRefererResult RedirectToReferer(this Controller controller, string defaultUrl = null)
		{
			return new RedirectToRefererResult(defaultUrl);
		}

		public static FileDataResult FileData(this Controller controller, FileData fileData)
		{
			return new FileDataResult(fileData);
		}

		public static string GetBaseUrl(this Controller controller)
		{
			return SlamCmsUrlHelper.GetBaseUrl();
		}

		public static string RenderView(this Controller controller, string viewName, object viewData = null, bool forJavascript = false)
		{
			return controller.ControllerContext.RenderView(viewName, viewData, forJavascript);
		}

		public static string RenderView(this ControllerContext controllerContext, string viewName, object viewData = null, bool forJavascript = false)
		{
			//Create memory writer 
			var sb = new StringBuilder();
			var memWriter = new StringWriter(sb);

			//Create fake http context to render the view 
			var fakeResponse = new HttpResponse(memWriter);
			var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse);
			var fakeControllerContext = new ControllerContext(new HttpContextWrapper(fakeContext), controllerContext.RouteData, controllerContext.Controller);
			fakeContext.User = controllerContext.HttpContext.User;

			var oldContext = HttpContext.Current;
			HttpContext.Current = fakeContext;

			//Use HtmlHelper to render partial view to fake context 
			var html = new HtmlHelper(new ViewContext(fakeControllerContext, new FakeView(), new ViewDataDictionary(), new TempDataDictionary(), memWriter), new ViewPage());
			html.RenderPartial(viewName, viewData);

			//Restore context 
			HttpContext.Current = oldContext;

			//Flush memory and return output 
			memWriter.Flush();
			var result = sb.ToString();

            if (forJavascript)
                result = Regex.Replace(result, "(\n|\r|\r\n)", string.Empty, RegexOptions.Compiled);
			
			return result;
		}

		private class FakeView : IView
		{
			public void Render(ViewContext viewContext, TextWriter writer)
			{
				throw new NotImplementedException();
			}
		}
	}
}
